package com.acooly.openapi.client.test.fudian;


import com.acooly.core.utils.Collections3;
import com.acooly.core.utils.Servlets;
import com.acooly.core.utils.Strings;
import com.acooly.core.utils.net.HttpResult;
import com.acooly.module.openapi.client.api.exception.ApiServerException;
import com.github.kevinsawicki.http.HttpRequest;
import com.google.common.collect.Maps;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

public class SimpleProxyServerFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(SimpleProxyServerFilter.class);


    /**
     * 代理转发目标地址
     */
    private String targetServer;

    private int readTimeout = 60000;
    private int connTimeout = 20000;
    private String contentType = HttpRequest.CONTENT_TYPE_FORM;
    private String charset = "utf-8";


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        if (Strings.isNotBlank(this.targetServer)) {
            return;
        }

        this.targetServer = filterConfig.getInitParameter("targetServer");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        if (Strings.isBlank(targetServer)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        StringBuilder sb = new StringBuilder();
        sb.append("\n").append(request.getScheme()).append(" ").append(Servlets.getRequestPath(request)).append("\n");
        Map<String, String> headers = Servlets.getHeaders(request, null);
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            sb.append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n");
        }

        InputStream in = null;
        HttpResult httpResult = null;
        String targetUrl = getTargetUrl(request);
        try {
            in = request.getInputStream();
            String body = IOUtils.toString(in, "utf-8");
            sb.append("\n").append(body).append("\n");
            httpResult = doRequest(targetUrl, body, headers);
        } catch (Exception e) {
            log.warn("转发失败:{}", e.getMessage());
        } finally {
            IOUtils.closeQuietly(in);
        }
        sb.append("Proxy to:").append(targetUrl).append("\n");
        sb.append("\nHttpStatus: ").append(httpResult.getStatus()).append("\n");
        for (Map.Entry<String, String> entry : httpResult.getHeaders().entrySet()) {
            sb.append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n");
        }
        sb.append("\n").append(httpResult.getBody());

        Servlets.writeResponse(response, sb.toString());

    }

    private String getTargetUrl(HttpServletRequest request) {
        return this.targetServer + Servlets.getRequestPath(request);
    }

    protected HttpResult doRequest(String url, String message, Map<String, String> headers) {

        HttpRequest httpRequest = HttpRequest.post(url)
                .headers(headers)
                .readTimeout(this.readTimeout)
                .connectTimeout(this.connTimeout)
                .contentType(this.contentType, this.charset)
                .send(message);

        if (httpRequest.code() >= 400) {
            throw new ApiServerException("status:" + httpRequest.code() + ", body:" + httpRequest.body());
        }

        HttpResult result = new HttpResult();
        result.setStatus(httpRequest.code());
        result.setBody(httpRequest.body());
        result.setHeaders(Maps.transformEntries(httpRequest.headers(), new Maps.EntryTransformer<String, List<String>, String>() {
            @Override
            public String transformEntry(@Nullable String key, @Nullable List<String> value) {
                if (Collections3.isEmpty(value)) {
                    return null;
                }
                if (value.size() == 0) {
                    return Collections3.getFirst(value);
                }
                return Collections3.convertToString(value, ",");
            }
        }));
        return result;
    }

    @Override
    public void destroy() {

    }
}
